最近忙，本来计划的一篇技术文章写了很久没写完，先发一篇短文凑数。

以前用Turbogears 1.x的时候觉得它有一些功能真是很方便，比如expose decorator。不过现在用web.py就没有这种东西了。

话说我改用web.py就是图它比较清爽这个优点，但能增加点方便还是好的。其实这个功能实现起来挺简单的，于是这两天就给web.py写了一个。

另外，现在RESTful的API都喜欢提供多种格式的结果返回（貌似这是twitter引领的风潮），于是顺便也给自己写的这个东东增加了这样的功能。

代码如下（其中obj2xml的代码来自这里 ）：

view plain
import json  
import web  
from web.contrib.template import render_mako  
class TGBaseHandler:  
    def __init__(self, templates_path):  
        self.mako_render = render_mako(  
            directories=[templates_path,],  
            input_encoding='utf-8',  
            output_encoding='utf-8'  
        )  
    # 默认支持两种 format render  
    # html render 使用 mako 模板  
    def html_render(self, page, result):  
        return getattr(self.mako_render, page)(**result)  
    def json_render(self, page, result):  
        return json.dumps(result)  
    # 自动调用相应的 format render  
    def render(self, page, format, result):  
        try:  
            render_func=getattr(self, format + '_render')  
        except AttributeError:  
            raise "Invalide render format!"  
        return render_func(page, result)  
# format : html/json/xml...  
# 默认为 html format，只需要提供 page 参数，其它 format 可以不需要 page 参数  
def expose(page='', format='html'):  
    def expose_wrapper(fn):  
        def format_wrapper(self, *args, **kwargs):  
            result=fn(self, *args, **kwargs)  
            if 'format' in result.keys(): # 自动选择相应的 format  
                format = result['format']  
                del result['format']  
            return self.render(page, format, result)  
        return format_wrapper  
    return expose_wrapper  

用法如下：

view plain
#...  
import obj2xml  
urls = (  
        "/", "index",  
        "/index", "index",  
        "/jsondata", "jsondata",  
        "/timeline/.?([^/?/.]+)", "timeline", # 自动取得 format 参数  
        )  
#...  
class BaseHandler(TGBaseHandler):  
    def __init__(self):  
        TGBaseHandler.__init__(self, ‘pathto/templates’) # 初始化 mako  
    # 可以在这里添加各种自定义的 format render  
    def xml_render(self, page, result):  
        return obj2xml.getXML(result)  
class index(BaseHandler):  
    @expose("index") # 默认 format 为 html  
    def GET(self):  
        return dict(url="/")  
class jsondata(BaseHandler):  
    @expose(format='json') # 指定用 json format render  
    def GET(self):  
        return dict(tweets=[{'id':'1234','text':'hello'},{'id':'2345','text':'world'}])  
class timeline(BaseHandler):  
    @expose() # 自动选择 format render  
    def GET(self, format):  
        return dict(format=format, tweets=[{'id':'1234','text':'hello'},{'id':'2345','text':'world'}]) # 注意，要在这里返回 format 参数  

这样访问 index 页面时返回的是用mako render出来的HTML，访问 jsondata 页面返回的就是一个 JSON 文本，访问 timeline.xml 和 timeline.json 就可以分别返回 XML 和 JSON 文本。

另外Turbogears 1.x的identity也很赞，回头有空也弄一个给web.py。